package cup.cqzj.auth.service;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cup.common.config.DsfAccessConfiguration;
import cup.common.utils.HttpRequestUtil;
import cup.core.log.exception.ServiceException;
import cup.core.redis.cache.CupRedis;
import cup.core.secure.utils.AuthUtil;
import cup.core.tool.utils.DigestUtil;
import cup.cqzj.auth.dto.DsfUserDTO;
import cup.cqzj.auth.vo.CheckCodeVo;
import cup.modules.auth.granter.PasswordTokenGranter;
import cup.modules.system.entity.User;
import cup.modules.system.service.IUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author : ruoyu
 * @date : 2022/8/18
 */
@Component
@AllArgsConstructor
@Slf4j
public class DsfTokenGranter {

	private final DsfAccessConfiguration dsfAccessConfiguration;
	private final CupRedis redis;
	private final IUserService userService;

	/**
	 * 获取 authorization_code 类型的accessToken
	 */
	private static final String AUTHORIZATION_TOKEN_URI = "/CQJGPT/rest/oauth2/token?client_id=#{client_id}" +
		"&client_secret=#{client_secret}&grant_type=authorization_code&redirect_uri=#{redirect_uri}" +
		"&code=#{code}";

	/**
	 * 获取监管侧 用户信息 这里只能获取 所有监管侧用户 然后过滤
	 */
	private static final String ORG_INFOS_URI = "/CQJGPT/rest/organization/getAllUser?access_token=#{access_token}";

	/**
	 * 获取loginId
	 */
	private static final String LOGIN_ID_URI = "/CQJGPT/rest/oauth2/loginid";

	/**
	 * 用户第三方登录临时key
	 */
	private static final String DSF_USER_CODE = "dsf:user:code:";

	/**
	 * 获取用户信息
	 */
	public DsfUserDTO getUserInfo(String code) {
		log.info("DsfTokenGranter->getUserInfo 获取用户信息:[{}]", code);
		String key = DSF_USER_CODE + code;
		String ss = redis.get(key);
		if (StringUtils.isNotBlank(ss)) {
			log.info("DsfTokenGranter->getUserInfo 获取用户信息:[{}] data:[{}]", code, ss);
			return JSONUtil.toBean(ss, DsfUserDTO.class);
		}
		//1.获取accessToken
		String authorizationAccessToken = getAuthorizationAccessToken(code);
		//2.获取用户loginId
		String loginId = getLoginId(authorizationAccessToken);
		//3.获取用户数据
		DsfUserDTO userInfo = getUserInfo(authorizationAccessToken, loginId);
		//4.登出用户 以免短时间二次登录 不用输入账号
		//缓存数据30m
		String jsonStr = JSONUtil.toJsonStr(userInfo);
		redis.setEx(key, jsonStr, Duration.ofMinutes(30));
		log.info("DsfTokenGranter->getUserInfo 获取用户信息:[{}] data:[{}]", code, jsonStr);
		return userInfo;
	}

	/**
	 * 验证用户信息
	 */
	public CheckCodeVo checkUser(DsfUserDTO userInfo) {
		CheckCodeVo checkCodeVo = new CheckCodeVo();
		checkCodeVo.setLoginId(userInfo.getLoginid());
		List<User> list = userService.list(new QueryWrapper<User>()
											   .eq("status", 1)
											   .eq("is_deleted", 0)
											   .eq("dsf_login_id", userInfo.getLoginid()));
		if (CollectionUtils.isEmpty(list)) {
			checkCodeVo.setStatus(3);
			return checkCodeVo;
		}
		if (list.size() > 1) {
			throw new ServiceException("数据错误,查询到绑定多个用户,请联系系统管理员");
		}
		User user = list.get(0);
		if (user.getIsActivity().equals(1)) {
			checkCodeVo.setStatus(1);
		} else if (user.getIsActivity().equals(-1) || user.getIsActivity().equals(2)) {
			checkCodeVo.setStatus(2);
		}

		return checkCodeVo;
	}

	/**
	 * 获取用户信息
	 */
	public User getUserEntity(String code) {
		DsfUserDTO cacheUserInfo = assertCacheUserInfo(code);

		User one = userService.getOne(new QueryWrapper<User>()
										  .eq("status", 1)
										  .eq("is_deleted", 0)
										  .eq("dsf_login_id", cacheUserInfo.getLoginid()));
		if (null == one) {
			throw new ServiceException("未获取到绑定用户信息,请确认是否绑定系统用户!");
		}
		return one;
	}

	/**
	 * 绑定用户
	 */
	public void bondExist(String code, String account, String password) {
		DsfUserDTO cacheUserInfo = assertCacheUserInfo(code);

		String hex = DigestUtil.hex(password);
		User user = userService.getOne(new QueryWrapper<User>()
										   .eq("account", account)
										   .eq("password", hex)
										   .eq("status", 1)
										   .eq("is_deleted", 0));
		if (StringUtils.isNotBlank(user.getDsfLoginId())) {
			throw new ServiceException("缓存过期 请重新登录[" + code + "]");
		}

		Date date = new Date();
		user.setDsfLoginId(cacheUserInfo.getLoginid());
		user.setDsfBondTime(date);
		user.setIsActivity(2);

		userService.updateById(user);
	}

	/**
	 * 绑定并新增用户
	 */
	public void bondAdd(String code, String account, String password) {
		DsfUserDTO cacheUserInfo = assertCacheUserInfo(code);
		//检测是否存在相同账号的账户
		int count = userService.count(new QueryWrapper<User>()
										  .eq("account", account)
										  .eq("is_deleted", 0));
		if (count > 0) {
			throw new ServiceException("账号:[" + account + "] 已存在,请确认后重新绑定");
		}
		//初始化用户基本数据
		Date date = new Date();
		User user = new User();
		user.setAccount(account);
		user.setName(StringUtils.isBlank(cacheUserInfo.getDisplayname()) ? cacheUserInfo.getLoginid() : cacheUserInfo.getDisplayname());
		user.setPassword(password);
		user.setTenantId("000000");
		user.setUserType(1);
		user.setIsDeleted(0);
		user.setStatus(-1);
		user.setDsfLoginId(cacheUserInfo.getLoginid());
		user.setDsfBondTime(date);
		user.setIsActivity(2);
		//初始化创建用户账户
		boolean submit = userService.submit(user);
//		if (Boolean.FALSE.equals(submit)) {
//			throw new ServiceException("新增绑定失败,请联系系统管理员!");
//		}
	}

	/**
	 * 激活用户
	 */
	public void activateUser(Long userId) {
		User user = userService.getOne(new QueryWrapper<User>()
										   .eq("id", userId)
//										   .eq("status", -1)
										   .eq("is_deleted", 0)
										   .eq("is_activity", 2));
		if (null == user) {
			throw new ServiceException("未查询到该用户[" + userId + "],请联系系统管理员:");
		}

		if (StringUtils.isBlank(user.getDeptId())) {
			throw new ServiceException("请绑定部门后再激活该用户!");
		}

		if (StringUtils.isBlank(user.getRoleId())) {
			throw new ServiceException("请绑定角色后再激活该用户!");
		}
		Date date = new Date();
		user.setStatus(1);
		user.setIsActivity(1);
		user.setActivityTime(date);
		user.setUpdateTime(date);
		user.setUpdateUser(AuthUtil.getUser().getUserId());
		userService.updateById(user);

	}

	public void removeCacheUserInfo(String code) {
		redis.del(DSF_USER_CODE + code);
	}

	private DsfUserDTO assertCacheUserInfo(String code) {
		DsfUserDTO cacheUserInfo = getCacheUserInfo(code);
		if (null == cacheUserInfo) {
			log.info("缓存过期 请重新登录[{}]", code);
			throw new ServiceException("缓存过期 请重新登录[" + code + "]");
		}
		return cacheUserInfo;
	}

	private DsfUserDTO getCacheUserInfo(String code) {
		String key = DSF_USER_CODE + code;
		String ss = redis.get(key);
		if (StringUtils.isBlank(ss)) {
			return null;
		}
		return JSONUtil.toBean(ss, DsfUserDTO.class);
	}

	/**
	 * 获取监管用户信息
	 */
	private DsfUserDTO getUserInfo(String authorizationAccessToken, String loginId) {
		log.info("DsfTokenGranter->getUserInfo 获取监管用户信息 token:[{}] loginId:[{}]", authorizationAccessToken, loginId);
		String url = dsfAccessConfiguration.getUrlPrefix() + ORG_INFOS_URI.replace("#{access_token}", authorizationAccessToken);
		String body = HttpRequestUtil
			.getPost(url)
			.execute()
			.body();
		if (StringUtils.isBlank(body)) {
			throw new ServiceException("未获取到监管侧用户信息:NULL");
		}
		List<DsfUserDTO> dsfUserDTOS = JSONUtil
			.parseObj(body)
			.getJSONArray("result")
			.toBean(new TypeReference<List<DsfUserDTO>>() {
			});
		if (CollectionUtils.isEmpty(dsfUserDTOS)) {
			throw new ServiceException("未获取到监管侧用户信息:ARRAY IS NULL");
		}
		Optional<DsfUserDTO> first = dsfUserDTOS.stream()
												.filter(x -> loginId.equals(x.getLoginid()))
												.findFirst();
		if (!first.isPresent()) {
			throw new ServiceException("未获取到监管侧用户信息:NOT FOUND BY ARRAY");
		}
		log.info("DsfTokenGranter->getUserInfo 获取监管用户信息 token:[{}] loginId:[{}] userInfo:[{}]"
			, authorizationAccessToken, loginId, JSONUtil.toJsonStr(first.get()));
		return first.get();
	}

	/**
	 * 获取loginId
	 */
	private String getLoginId(String authorizationAccessToken) {
		log.info("DsfTokenGranter->getLoginId 准备loginId accessToken:[{}]", authorizationAccessToken);
		String loginId = HttpRequestUtil
			.getPost(dsfAccessConfiguration.getUrlPrefix() + LOGIN_ID_URI)
			.header("Authorization", "Bearer " + authorizationAccessToken)
			.execute()
			.body();
		if (StringUtils.isBlank(loginId)) {
			throw new ServiceException("未获取到loginId");
		}
		log.info("DsfTokenGranter->getLoginId 获取到loginId accessToken:[{}] loginId:[{}]", authorizationAccessToken, loginId);
		return loginId;
	}

	/**
	 * 获取 授权code
	 */
	private String getAuthorizationAccessToken(String code) {
		log.info("DsfTokenGranter->getAuthorizationAccessToken 准备获取授权code code:[{}]", code);
		String url = dsfAccessConfiguration.getUrlPrefix() + AUTHORIZATION_TOKEN_URI
			.replace("#{client_id}", dsfAccessConfiguration.getClientId())
			.replace("#{client_secret}", dsfAccessConfiguration.getClientSecret())
			.replace("#{redirect_uri}", dsfAccessConfiguration.getRedirectUri())
			.replace("#{code}", code);
		String body = HttpRequestUtil
			.getPost(url)
			.execute()
			.body();
		if (StringUtils.isBlank(body)) {
			throw new ServiceException("获取授权令牌错误:返回值NULL");
		}
		JSONObject jsonObject = JSONUtil.parseObj(body);
		String accessToken = jsonObject.getStr("access_token");
		if (StringUtils.isBlank(accessToken)) {
			throw new ServiceException("获取授权令牌错误:未获取到accToken[" + body + "]");
		}
		log.info("DsfTokenGranter->getAuthorizationAccessToken code:[{}] token:[{}]", code, accessToken);
		return accessToken;
	}

	/**
	 * 绑定一网通办账号
	 */
	public void easyBondDdd(Long userId, String loginId) {
		//查询用户是否已经绑定
		User user = userService.getOne(new QueryWrapper<User>()
										   .eq("id", userId)
										   .eq("status", 1)
										   .eq("is_deleted", 0));
		if (null == user) {
			throw new ServiceException("未查询到该用户信息");
		}
		//是否已经绑定
		if (StringUtils.isNotBlank(user.getDsfLoginId()) && user.getIsActivity().equals(1)) {
			throw new ServiceException("该账号已绑定第三方用户");
		}
		//查询loginid是否已经存在并绑定
		int count = userService.count(new QueryWrapper<User>()
										  .eq("status", 1)
										  .eq("is_deleted", 0)
										  .eq("dsf_login_id", loginId)
										  .eq("is_activity", 1));
		if (count > 0) {
			throw new ServiceException("["+loginId+"]已绑定到该系统!");
		}
		//绑定账号
		Date date = new Date();
		user.setDsfLoginId(loginId);
		user.setDsfBondTime(date);
		user.setIsActivity(1);
		user.setActivityTime(date);
		user.setUpdateTime(date);
		user.setUpdateUser(AuthUtil.getUserId());
		userService.updateById(user);
	}

	public void easyUnbindAdd(Long userId) {
		//查询用户是否已经绑定
		User user = userService.getOne(new QueryWrapper<User>()
										   .eq("id", userId)
										   .eq("status", 1)
										   .eq("is_deleted", 0));

		if (null == user) {
			throw new ServiceException("未查询到该用户信息");
		}
		if(!user.getIsActivity().equals(1)){
			throw new ServiceException("未查询到已绑定第三方账号");
		}
		Date date = new Date();
		user.setUpdateTime(date);
		user.setUpdateUser(AuthUtil.getUserId());
		user.setIsActivity(-1);
		user.setActivityTime(date);
		user.setDsfLoginId("");
		userService.updateById(user);
	}
}
